/******************************************************************************* 
  Copyright (C), 1988-2020, zeno Tech. Co., Ltd.
  Description:   AUDIO模块  
  Function List:     
  History:
    <wangmc -- 2014-12-15>  创建
*******************************************************************************/ 

/*=============================================================================
                                 Includes                                  
 =============================================================================*/
#include "audioPriv.h"
//#include "audioHiAin.h"
//#include "audioHiAout.h"
//#include "audioHiAenc.h"
//#include "audioHiAdec.h"



/*=============================================================================
                               Macro Definition
 =============================================================================*/
#define LINEIN_ADC_BITS 8
#define LINEIN_ADC_THRESHOLD 64
/*=============================================================================
                        Local Structures and Typedef 
 =============================================================================*/


/*=============================================================================
                             Extern Variables                                  
=============================================================================*/


/*=============================================================================
                             Local Variables                                  
 =============================================================================*/
AUDIO_ctl_t audioCtl_g;
static int hasCreated_s = 0;
static const char* asoundPath = "/proc/asound/cards";

/*=============================================================================
                             Function Definition                                  
 =============================================================================*/

/*******************************************************************************
  Function:     AI_CreatTrdAiAenc
  Description:  创建音频输入绑定音频编码线程
  Input:        - pAudioCtl: 音频控制结构体指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int AUDIO_CreatTrdAiAenc(AUDIO_ctl_t *pAudioCtl)
{  
    int ret;
#if 0   
    struct sched_param sched;
    
    sched.sched_priority = 1;

    pAudioCtl->bAinStart = 1;
    
    ret = pthread_create(&pAudioCtl->aiToAencThd, 0, 
                            AUDIOENC_UserBindAi, pAudioCtl);
    if (ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        return -1;
    }

    pthread_setschedparam(pAudioCtl->aiToAencThd, SCHED_RR, &sched);
#endif    
    return 0;
}

/*******************************************************************************
  Function:     AI_DestoryTrdAiAenc
  Description:  销毁音频输入绑定音频编码线程
  Input:        - pAudioCtl: 音频控制结构体指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int AUDIO_DestoryTrdAiAenc(AUDIO_ctl_t *pAudioCtl)
{
    pAudioCtl->bAinStart = 0;
    
    pthread_join(pAudioCtl->aiToAencThd, 0);

    return 0;
}
 
/*******************************************************************************
  Function:     AI_GetCfg
  Description:  获取音频输入参数
  Input:        - pAiCtl: 音频编码通道控制结构体指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AUDIO_GetCfg(AIO_ctl_t *pAioCtl)
{
#if 0
    AIO_ATTR_S *pAiAttr;
    AIO_ATTR_S *pAoAttr;
    
    pAiAttr = &pAioCtl->aiAttr[AI_DEV_ID0];
        
    pAioCtl->aiDevId[AI_DEV_ID0] = AI_DEV_ID0;
    pAioCtl->aiChn = pAioCtl->audioInTrack;   

    pAiAttr->enSamplerate       = AUDIO_SAMPLE_RATE_48000;
    pAiAttr->enWorkmode         = AIO_MODE_I2S_MASTER;
    pAiAttr->u32PtNumPerFrm     = 256*3;
    pAiAttr->enBitwidth         = AUDIO_BIT_WIDTH_16;
    pAiAttr->u32EXFlag          = 0;
    pAiAttr->u32FrmNum          = 30;
    pAiAttr->u32ClkSel          = 0;
    pAiAttr->u32ChnCnt          = 1;
    pAiAttr->enSoundmode        = AUDIO_SOUND_MODE_MONO;
#if defined(AUDIO_HI3559AV100)||defined(AUDIO_HI3516CV500)||defined(AUDIO_HI3516EV200)||defined(AUDIO_HI3519AV100)
    pAiAttr->enI2sType      = AIO_I2STYPE_EXTERN;
#endif

    pAiAttr = &pAioCtl->aiAttr[AI_DEV_ID1];
    
    pAioCtl->aiDevId[AI_DEV_ID1] = AI_DEV_ID1;
    pAioCtl->aiChn = pAioCtl->audioInTrack;   

    pAiAttr->enSamplerate		= AUDIO_SAMPLE_RATE_16000;
	pAiAttr->enWorkmode 		= AIO_MODE_I2S_MASTER;
	pAiAttr->u32PtNumPerFrm 	= 256;
	pAiAttr->enBitwidth 		= AUDIO_BIT_WIDTH_16;
	pAiAttr->u32EXFlag			= 0;
	pAiAttr->u32FrmNum			= 30;
	pAiAttr->u32ClkSel			= 1;
	if (2 == pAioCtl->audioInTrack)
	{
    	pAiAttr->u32ChnCnt		= 2;
        pAiAttr->enSoundmode	= AUDIO_SOUND_MODE_STEREO;
	}
	else
	{
#if defined(AUDIO_HI3516EV200)
	    pAiAttr->u32ChnCnt		= 1;
#else
		pAiAttr->u32ChnCnt		= 2;
#endif
        pAiAttr->enSoundmode	= AUDIO_SOUND_MODE_MONO;
	}
    pAiAttr->u32ChnCnt		    = 8;

#if defined(AUDIO_HI3559AV100)||defined(AUDIO_HI3516CV500)||defined(AUDIO_HI3516EV200)||defined(AUDIO_HI3519AV100)
	pAiAttr->enI2sType      = AIO_I2STYPE_EXTERN;
#endif

#if defined(AUDIO_HI3519)||defined(AUDIO_HI3519V101)||defined(AUDIO_HI3516CV300)||defined(AUDIO_HI3559AV100)||defined(AUDIO_HI3516CV500)||defined(AUDIO_HI3516EV200)||defined(AUDIO_HI3519AV100)
    AI_TALKVQE_CONFIG_S *pAiTalkVqe;
    pAiTalkVqe = &pAioCtl->aiVqeAttr;

    pAiTalkVqe->u32OpenMask          = AI_TALKVQE_MASK_AEC 
                                        | AI_TALKVQE_MASK_HPF
                                        | AI_TALKVQE_MASK_AGC
                                        | AI_TALKVQE_MASK_ANR;
    pAiTalkVqe->s32WorkSampleRate    = AUDIO_SAMPLE_RATE_8000;
    pAiTalkVqe->s32FrameSample       = 320;
    pAiTalkVqe->enWorkstate          = VQE_WORKSTATE_COMMON;
    pAiTalkVqe->stAecCfg.bUsrMode    = HI_FALSE;
    pAiTalkVqe->stAecCfg.s8CngMode   = 0;
    pAiTalkVqe->stAgcCfg.bUsrMode    = HI_FALSE;
    pAiTalkVqe->stAnrCfg.bUsrMode    = HI_FALSE;
	pAiTalkVqe->stHpfCfg.bUsrMode    = HI_TRUE;
    pAiTalkVqe->stHpfCfg.enHpfFreq   = AUDIO_HPF_FREQ_150;
#if !defined(AUDIO_HI3559AV100) && !defined(AUDIO_HI3516CV500) && !defined(AUDIO_HI3516EV200) && !defined(AUDIO_HI3519AV100)
	pAiTalkVqe->stHdrCfg.bUsrMode    = HI_FALSE;
#endif
#else
    AI_VQE_CONFIG_S *pAiVqeAttr;
    pAiVqeAttr = &pAioCtl->aiVqeAttr;

    pAiVqeAttr->bAecOpen        = HI_TRUE;
	pAiVqeAttr->bAnrOpen            = HI_TRUE;
#ifdef HIMPP_V2_0
	pAiVqeAttr->bAgcOpen            = HI_TRUE;
    pAiVqeAttr->bHpfOpen            = HI_FALSE;
    pAiVqeAttr->bRnrOpen            = HI_FALSE;
	pAiVqeAttr->bEqOpen             = HI_FALSE;
	pAiVqeAttr->bHdrOpen            = HI_FALSE;
	pAiVqeAttr->stAecCfg.bUsrMode   = HI_FALSE;
	pAiVqeAttr->stAecCfg.s8CngMode  = AUDIO_AEC_MODE_CLOSE;
    pAiVqeAttr->stAgcCfg.bUsrMode   = HI_TRUE;
    pAiVqeAttr->stAgcCfg.s8TargetLevel = -4;
    pAiVqeAttr->stAgcCfg.s8NoiseFloor = -40;
    pAiVqeAttr->stAgcCfg.s8MaxGain = 3;
    pAiVqeAttr->stAgcCfg.s8AdjustSpeed = 1;
    pAiVqeAttr->stAgcCfg.s8ImproveSNR = 2;
    pAiVqeAttr->stAgcCfg.s8UseHighPassFilt = 0;
    pAiVqeAttr->stAgcCfg.s8OutputMode = 0;
    pAiVqeAttr->stAgcCfg.s16NoiseSupSwitch = 0;
    pAiVqeAttr->stAnrCfg.bUsrMode   = HI_TRUE;
    pAiVqeAttr->stAnrCfg.s16NrIntensity = 15;
    pAiVqeAttr->stAnrCfg.s16NoiseDbThr = 55;
    pAiVqeAttr->stAnrCfg.s8SpProSwitch = 1;
    pAiVqeAttr->stHpfCfg.bUsrMode   = HI_FALSE;
	pAiVqeAttr->enWorkstate         = VQE_WORKSTATE_MUSIC;
	pAiVqeAttr->s32WorkSampleRate   = AUDIO_SAMPLE_RATE_8000;
#else
    AI_HPF_ATTR_S *pAiHpfAttr;
	pAiHpfAttr = &pAioCtl->aiHpfAttr;

	pAiHpfAttr->bHpfOpen            = HI_FALSE;
	pAiHpfAttr->stHpfCfg.enHpfFreq  = AUDIO_HPF_FREQ_150;
    pAiVqeAttr->bAlcOpen            = HI_TRUE;
    pAiVqeAttr->stAecCfg.enAecMode  = AUDIO_AEC_MODE_SPEAKER;
    pAiVqeAttr->s32SampleRate       = AUDIO_SAMPLE_RATE_8000;
    pAiVqeAttr->stAlcCfg.s32MinLev  = -16;
	pAiVqeAttr->stAlcCfg.s32MaxLev  = -4;
	pAiVqeAttr->stAlcCfg.u32MaxGain = 12;
#endif
	pAiVqeAttr->s32FrameSample      = 320;
#endif

	pAoAttr = &pAioCtl->aoAttr;

	pAioCtl->aoDevId = AO_DEV_ID;
    pAioCtl->aoChn = 0;   

    pAoAttr->enSamplerate		= AUDIO_SAMPLE_RATE_48000;
	pAoAttr->enWorkmode 		= AIO_MODE_I2S_MASTER;
	pAoAttr->u32PtNumPerFrm 	= 768;
	pAoAttr->enBitwidth 		= AUDIO_BIT_WIDTH_16;
	pAoAttr->u32EXFlag			= 0;
	pAoAttr->u32FrmNum			= 30;
	pAoAttr->u32ClkSel			= 0;
	if (2 == pAioCtl->audioOutTrack)
	{
    	pAoAttr->u32ChnCnt		= 2;
        pAoAttr->enSoundmode	= AUDIO_SOUND_MODE_STEREO;
	}
	else
	{
#if defined(AUDIO_HI3516EV200)
		pAoAttr->u32ChnCnt		= 1;
#else
		pAoAttr->u32ChnCnt		= 2;
#endif
        pAoAttr->enSoundmode	= AUDIO_SOUND_MODE_MONO;
	}

    pAoAttr->enSoundmode	= AUDIO_SOUND_MODE_MONO;
	pAoAttr->u32ChnCnt		= 1;

#if defined(AUDIO_HI3559AV100)||defined(AUDIO_HI3516CV500)||defined(AUDIO_HI3516EV200)||defined(AUDIO_HI3519AV100)
	pAoAttr->enI2sType		= AIO_I2STYPE_EXTERN;
#endif

#ifdef HIMPP_V2_0
    AO_VQE_CONFIG_S *pAoVqeAttr;
    pAoVqeAttr = &pAioCtl->aoVqeAttr;

#if defined(AUDIO_HI3519)||defined(AUDIO_HI3519V101)||defined(AUDIO_HI3516CV300)||defined(AUDIO_HI3559AV100)||defined(AUDIO_HI3516CV500)||defined(AUDIO_HI3516EV200)||defined(AUDIO_HI3519AV100)
    pAoVqeAttr->u32OpenMask = AO_VQE_MASK_HPF 
                                | AO_VQE_MASK_ANR
                                | AO_VQE_MASK_AGC;
#else
    pAoVqeAttr->bAgcOpen            = HI_FALSE;
    pAoVqeAttr->bHpfOpen            = HI_FALSE;
    pAoVqeAttr->bAnrOpen            = HI_TRUE;
	pAoVqeAttr->bEqOpen             = HI_FALSE;
#endif
    pAoVqeAttr->stAnrCfg.bUsrMode   = HI_TRUE;
    pAoVqeAttr->stAnrCfg.s16NrIntensity = 10;
    pAoVqeAttr->stAnrCfg.s16NoiseDbThr = 55;
    pAoVqeAttr->stAnrCfg.s8SpProSwitch = 1;
    pAoVqeAttr->stHpfCfg.bUsrMode   = HI_FALSE;
	pAoVqeAttr->enWorkstate         = VQE_WORKSTATE_MUSIC;
	pAoVqeAttr->s32WorkSampleRate   = AUDIO_SAMPLE_RATE_8000;
	pAoVqeAttr->s32FrameSample      = 256;
#endif   

#endif
    return 0;
}

/*******************************************************************************
  Function:     AI_Creat
  Description:  创建音频输入输出通道
  Input:        - pAioCtl: 音频编码通道控制结构体指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int AUDIO_Creat(AIO_ctl_t *pAioCtl)
{
#if 0
    int ret;
    unsigned int audioMask = 0;
    AIO_ATTR_S *pAioAttr;
	
	/* 在 AI/AO 设备都禁用时再调用reset */
    if (1 == audioCtl_g.isAcodecReset)
    {
        audioCtl_g.isAcodecReset = 0;

        ret = AUDIO_ResetAcodec();
        if (ret)
        {
            LOG_PrintError("AUDIO_ResetAcodec faile!\n");
            return -1;
        }
    }

    if (pAioCtl->audioInChn)
    {
        audioMask |= 1 << 0; 
        
        pAioAttr = &pAioCtl->aiAttr;

        ret = AIN_CreateDev(pAioCtl->aiDevId, pAioAttr);
        if (ret)
        {
            LOG_PrintError("AIN_CreateDev faile!\n");
            return -1;
        }

        ret = AIN_CreateChn(pAioCtl->aiDevId, pAioCtl->aiChn);
        if (ret)
        {
            LOG_PrintError("AIN_CreateChn faile!\n");
            return -1;
        }

        if (((AUDIO_SAMPLE_RATE_8000 == pAioAttr->enSamplerate)
            || (AUDIO_SAMPLE_RATE_11025 == pAioAttr->enSamplerate)
            || (AUDIO_SAMPLE_RATE_12000 == pAioAttr->enSamplerate)
            || (AUDIO_SAMPLE_RATE_16000 == pAioAttr->enSamplerate))
            && (AUDIO_SOUND_MODE_MONO == pAioAttr->enSoundmode)
            && (AUDIO_BIT_WIDTH_16 == pAioAttr->enBitwidth))
        {
            audioCtl_g.isSetVqe = 1;

            ret = AIN_SetVqeAttr(pAioCtl->aiDevId, 
                                    pAioCtl->aiChn, 
                                    &pAioCtl->aiVqeAttr
                                #ifndef HIMPP_V2_0
                                    ,&pAioCtl->aiHpfAttr
                                #endif
                                );
            if (ret)
            {
                LOG_PrintError("AIN_SetVqeAttr faile!\n");
                return -1;
            }
        }
        else
        {
            audioCtl_g.isSetVqe = 0;
        }

        ret = AUDIO_CreatTrdAiAenc(&audioCtl_g);
    	if (ret)
    	{
    	    LOG_PrintError("AUDIOENC_Create failed \n");
    	    return -1;
    	}

    	ret = AUDIO_AiDownPower(1);
    	if (ret)
        {
            LOG_PrintError("AUDIO_AiDownPower fialed !\n");
            return -1;
        }
    }

    if (pAioCtl->audioOutChn)
    {
        audioMask |= 1 << 1; 
        
        pAioAttr = &pAioCtl->aoAttr;

        ret = AOUT_CreateDev(pAioCtl->aoDevId, pAioAttr);
        if (ret)
        {
            LOG_PrintError("AOUT_CreateDev faile!\n");
            return -1;
        }

        ret = AOUT_CreateChn(pAioCtl->aoDevId, pAioCtl->aoChn);
        if (ret)
        {
            LOG_PrintError("AOUT_CreateChn faile!\n");
            return -1;
        }

#ifdef HIMPP_V2_0
        AUDIO_TRACK_MODE_E trackMode;

        trackMode = AUDIO_TRACK_NORMAL;
        ret = HI_MPI_AO_SetTrackMode(pAioCtl->aoDevId, trackMode);
        if (ret)
        {
            LOG_PrintError("AOUT_CreateChn faile!\n");
            return -1;
        }

        /* 音频输出音质增强功能，应用未实现，底层先自己调用 */
        AOUT_SetVqeAttr(pAioCtl->aoDevId, pAioCtl->aoChn, &pAioCtl->aoVqeAttr);
#endif

        ret = AUDIO_AoDownPower(1);
        if (ret)
        {
            LOG_PrintError("AUDIO_AoDownPower fialed !\n");
            return -1;
        }
    }

    if (audioMask)
    {
        ret = AUDIO_CfgAcodec(pAioAttr->enSamplerate);
        if (ret)
        {
            LOG_PrintError("AUDIO_CfgAcodec faile!\n");
            return -1;
        }

        if (audioMask&(1 << 0))
        {
            ret = AUDIO_SetAiLineMic(pAioCtl->audioInMode);
            if (ret)
            {
                LOG_PrintError("AUDIO_SetAiLineMic faile!\n");
                return -1;
            }
        }
    }
#endif
    return 0;
}

/*******************************************************************************
  Function:     AI_Destory
  Description:  注销音频输入输出通道
  Input:        - pAioCtl: 音频编码通道控制结构体指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int AUDIO_Destory(AIO_ctl_t *pAioCtl)
{
    int ret;

    /*if (pAioCtl->audioInChn)
    {
        ret = AUDIO_DestoryTrdAiAenc(&audioCtl_g);
        if (ret)
    	{
    	    LOG_PrintError("AENC_DestoryTrdAiAenc fialed !\n");
            return -1;
    	} 
    	
        ret = AIN_Destroy(pAioCtl->aiDevId, pAioCtl->aiChn);
        if (ret)
        {
            LOG_PrintError("AIN_CreateChn failed!\n");
            return -1;
        }
    }

    if (pAioCtl->audioOutChn)
    {
        ret = AOUT_Destroy(pAioCtl->aoDevId, pAioCtl->aoChn);
        if (ret)
        {
            LOG_PrintError("AOUT_Destroy failed!\n");
            return -1;
        }
    }*/

    return 0;
}

/*******************************************************************************
  Function:     AUDIO_StopAll
  Description:  停止音频所有的输入输出通道
  Input:        无
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AUDIO_StopAll(void)
{
#if 0
    int i, ret;
    AENC_ctl_t *pAencCtl;
    ADEC_ctl_t *pAdecCtl;
    
    for (i = 0; i < AENC_STREAM_PER_CHN; i++)
    {
        pAencCtl = audioCtl_g.pEncCtls[i];
        if (!pAencCtl)
        {
            continue;
        }

        pAencCtl->oldAencState = pAencCtl->aencState;
        
        if (pAencCtl->aencState == AENC_STREAM_STOP)
        {
            continue;
        }

        pthread_mutex_lock(&audioCtl_g.aiAencMutex);
        
        ret = AUDIOENC_Destroy(pAencCtl->aencChn);
        if (ret)
        {
            LOG_PrintError("AUDIOENC_Destroy fialed !\n");
            pthread_mutex_unlock(&audioCtl_g.aiAencMutex);
            return -1;
        }

        pAencCtl->aencState = AENC_STREAM_STOP;

        pthread_mutex_unlock(&audioCtl_g.aiAencMutex);

    }

    for (i = 0; i < ADEC_STREAM_PER_CHN; i++)
    {
        pAdecCtl = audioCtl_g.pAdecCtls[i];
        if (!pAdecCtl)
        {
            continue;
        }

        pAdecCtl->oldAdecState = pAdecCtl->adecState;

        if (pAdecCtl->adecState == ADEC_STATUS_STOP)
        {
            continue;
        }

        ret = AUDIODEC_UnbindAo(pAdecCtl->adecChn, 
                                AO_DEV_ID, 
                                audioCtl_g.aioCtl.aoChn);
        if (ret)
        {
            LOG_PrintError("AUDIODEC_UnbindAo fialed !\n");
            return -1;
        }
        
        ret = AUDIODEC_Destroy(pAdecCtl->adecChn);
        if (ret)
        {
            LOG_PrintError("AUDIODEC_Destroy fialed !\n");
            return -1;
        }  

        pAdecCtl->adecState = ADEC_STATUS_STOP;
    }

    ret = AUDIO_Destory(&audioCtl_g.aioCtl);
    if (ret)
    {
        LOG_PrintError("AI_Destory fialed !\n");
        return -1;
    }
#endif
    return 0;
}

/*******************************************************************************
  Function:     AUDIO_StartAll
  Description:  启动音频所有的输入输出通道
  Input:        无
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AUDIO_StartAll(void)
{
    int i, ret;
    AENC_ctl_t *pAencCtl;
    ADEC_ctl_t *pAdecCtl;
#if 0
    ret = AUDIO_Creat(&audioCtl_g.aioCtl);
    if (ret)
    {
        LOG_PrintError("AUDIO_Creat fialed !\n");
        return -1;
    }
        
    for (i = 0; i < AENC_STREAM_PER_CHN; i++)
    {
        pAencCtl = audioCtl_g.pEncCtls[i];
        if (!pAencCtl)
        {
            continue;
        }

        if (pAencCtl->oldAencState == AENC_STREAM_STOP)
        {
            continue;
        }
        
        if (pAencCtl->aencState == AENC_STREAM_START)
        {
            continue;
        }
        
        ret = AUDIOENC_Create(pAencCtl->aencChn, &pAencCtl->aencAttr);
        if (ret)
        {
            LOG_PrintError("AUDIOENC_Create failed \n");
            return -1;
        }

        pAencCtl->aencState = AENC_STREAM_START;
    }

    for (i = 0; i < ADEC_STREAM_PER_CHN; i++)
    {
        pAdecCtl = audioCtl_g.pAdecCtls[i];
        if (!pAdecCtl)
        {
            continue;
        }

        if (pAdecCtl->oldAdecState == ADEC_STATUS_STOP)
        {
            continue;
        }

        if (pAdecCtl->adecState == ADEC_STATUS_START)
        {
            continue;
        }

        pAdecCtl->frameSeq = 0;

        ret = AUDIODEC_Create(pAdecCtl->adecChn, &pAdecCtl->adecAttr);
    	if (ret)
    	{
    	    LOG_PrintError("AUDIODEC_Create failed \n");
    	    return -1;
    	}
        
    	ret = AUDIODEC_BindAo(pAdecCtl->adecChn, 
                            	AO_DEV_ID, 
                            	audioCtl_g.aioCtl.aoChn);
    	if (ret)
    	{
    		LOG_PrintError("AUDIODEC_BindAo failed \n");
    		return -1;
    	}

        memset(&pAdecCtl->packDecStream, 0, sizeof(PACK_decStreamInfo_t));

    	pAdecCtl->adecState = ADEC_STATUS_START;
    }
#endif
    return 0;
}

/*******************************************************************************
  Function:     AUDIO_SetFormat
  Description:  设置音频通道属性
  Input:        - frequency: 采样率
                - depth: 采样宽度
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int AUDIO_SetFormat(int frequency, int depth)
{
    int ret;
#if 0   
    AUDIO_BIT_WIDTH_E bitwidth; 
    AIO_ATTR_S *pAiAttr;
    AIO_ATTR_S *pAoAttr;
#if defined(AUDIO_HI3519)||defined(AUDIO_HI3519V101)||defined(AUDIO_HI3516CV300)||defined(AUDIO_HI3559AV100)||defined(AUDIO_HI3516CV500)||defined(AUDIO_HI3516EV200)||defined(AUDIO_HI3519AV100)
    AI_TALKVQE_CONFIG_S *pAiVqeAttr;
#else
    AI_VQE_CONFIG_S *pAiVqeAttr;
#endif

    pAiAttr = &audioCtl_g.aioCtl.aiAttr;
    pAoAttr = &audioCtl_g.aioCtl.aoAttr;
    pAiVqeAttr = &audioCtl_g.aioCtl.aiVqeAttr;

    switch(depth)
    {
        case 8:
            bitwidth = AUDIO_BIT_WIDTH_8;
            break;
        case 16:
            bitwidth = AUDIO_BIT_WIDTH_16;
            break;
#ifdef HIMPP_V2_0
        case 24:
            bitwidth = AUDIO_BIT_WIDTH_24;
            break; 
#else
        case 32:
            bitwidth = AUDIO_BIT_WIDTH_32;
            break;
#endif
        default:
            LOG_PrintError("depth %d is invalid!\n", depth);
            return -1;
    }

    if ((pAiAttr->enSamplerate != frequency) ||
        (pAiAttr->enBitwidth != bitwidth))
    {
        pAiAttr->enSamplerate = frequency;
        pAiAttr->enBitwidth = bitwidth;
        pAoAttr->enSamplerate = frequency;
        pAoAttr->enBitwidth = bitwidth;
#ifdef HIMPP_V2_0
        pAiVqeAttr->s32WorkSampleRate = frequency;
#else
        pAiVqeAttr->s32SampleRate = frequency;
#endif
        ret = AUDIO_StopAll();
        if (ret)
        {
            LOG_PrintError("AUDIO_StopAll failed \n");
            return -1;
        }
        
        ret = AUDIO_StartAll();
        if (ret)
        {
            LOG_PrintError("AUDIO_StartAll failed \n");
            return -1;
        }
    }
#endif
    return 0;
}

/*******************************************************************************
  Function:     AUDIO_GetConfig
  Description:  获取音频配置参数
  Input:        无
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AUDIO_GetConfig(void)
{
    int i, audioNums;
    int gpio, level;
    cJSON *pJson, *pSubItem, *pItem, *pTmpItem;
    
    pJson = CFG_GetItem(NULL, "audio");
    if (!pJson)
    {
        LOG_PrintInfo("Not support audio!\n");
        return 0; 
    }
    
    pSubItem = cJSON_GetObjectItem(pJson, "audioIn");
    if (!pSubItem)
    {
        audioCtl_g.aioCtl.audioInChn = 0;
        LOG_PrintWarn("Fail to get config audioIn!\n");
    }
    else
    {
        audioNums = cJSON_GetArraySize(pSubItem);
        audioCtl_g.aioCtl.audioInChn = audioNums;

        for (i = 0; i < audioNums; i++)
        {
            pItem = cJSON_GetArrayItem(pSubItem, i);
            if (!pItem)
            {
                LOG_PrintError("Fail to get config audioIn!\n");
                return -1; 
            }

            pTmpItem = cJSON_GetObjectItem(pItem, "track");
            if (!pTmpItem)
            {
                LOG_PrintError("Fail to get config track!\n");
                return -1; 
            }
            audioCtl_g.aioCtl.audioInTrack = pTmpItem->valueint;

            pTmpItem = cJSON_GetObjectItem(pItem, "mode");
            if (!pTmpItem)
            {
                LOG_PrintError("Fail to get config mode!\n");
                return -1; 
            }
            audioCtl_g.aioCtl.audioInMode = pTmpItem->valueint;

            pTmpItem = cJSON_GetObjectItem(pItem, "gpioIndex");
            if (pTmpItem)
            { 
                gpio = pTmpItem->valueint;

                pTmpItem = cJSON_GetObjectItem(pItem, "gpioLevel");
                if (!pTmpItem)
                {
                    LOG_PrintError("Fail to get config gpioLevel!\n");
                    return -1; 
                }
                level = pTmpItem->valueint;

                GPIO_Get(gpio);
                GPIO_SetDir(gpio, 1);
                GPIO_SetLevel(gpio, level); 
            }

            pTmpItem = cJSON_GetObjectItem(pItem, "lineinGpio");
            if (pTmpItem)
            { 
                audioCtl_g.aioCtl.lineinGpio = pTmpItem->valueint;

                pTmpItem = cJSON_GetObjectItem(pItem, "lineinLevel");
                if (!pTmpItem)
                {
                    LOG_PrintError("Fail to get config gpioLevel!\n");
                    return -1; 
                }
                audioCtl_g.aioCtl.lineinLevel = pTmpItem->valueint;
            }

            pTmpItem = cJSON_GetObjectItem(pItem, "adChn");
            if (pTmpItem)
            { 
                audioCtl_g.aioCtl.lineinAdcChn = pTmpItem->valueint;

                pTmpItem = cJSON_GetObjectItem(pItem, "adLevel");
                if (!pTmpItem)
                {
                    LOG_PrintError("Fail to get config gpioLevel!\n");
                    return -1; 
                }
                audioCtl_g.aioCtl.lineinAdcLevel = pTmpItem->valueint;
            }
        }
    }

    pSubItem = cJSON_GetObjectItem(pJson, "audioOut");
    if (!pSubItem)
    {
        audioCtl_g.aioCtl.audioOutChn = 0;
        LOG_PrintWarn("Fail to get config audioOut!\n");
    }
    else
    {
        audioNums = cJSON_GetArraySize(pSubItem);
        audioCtl_g.aioCtl.audioOutChn = audioNums;

        for (i = 0; i < audioNums; i++)
        {
            pItem = cJSON_GetArrayItem(pSubItem, i);
            if (!pItem)
            {
                LOG_PrintError("Fail to get config audioOut!\n");
                return -1; 
            }

            pTmpItem = cJSON_GetObjectItem(pItem, "track");
            if (!pTmpItem)
            {
                LOG_PrintError("Fail to get config track!\n");
                return -1; 
            }
            audioCtl_g.aioCtl.audioOutTrack = pTmpItem->valueint;

            pTmpItem = cJSON_GetObjectItem(pItem, "mode");
            if (!pTmpItem)
            {
                LOG_PrintError("Fail to get config mode!\n");
                return -1; 
            }

            pTmpItem = cJSON_GetObjectItem(pItem, "gpioIndex");
            if (pTmpItem)
            { 
                audioCtl_g.aioCtl.lineoutGpio = pTmpItem->valueint;

                pTmpItem = cJSON_GetObjectItem(pItem, "gpioLevel");
                if (!pTmpItem)
                {
                    LOG_PrintError("Fail to get config gpioLevel!\n");
                    return -1; 
                }
                audioCtl_g.aioCtl.lineoutLevel = pTmpItem->valueint;

                pTmpItem = cJSON_GetObjectItem(pItem, "gpioType");
                if (!pTmpItem)
                {
                    LOG_PrintError("Fail to get config gpioType!\n");
                    return -1; 
                }
                audioCtl_g.aioCtl.lineoutType = pTmpItem->valueint;
            }
        }
    }

#ifndef __HuaweiLite__
    //cJSON_Delete(pJson);
#endif

    LOG_PrintInfo("audio in chn %d ,audio out chn %d\n",
                    audioCtl_g.aioCtl.audioInChn,
                    audioCtl_g.aioCtl.audioOutChn);

#if 0
    pJson = CFG_GetItem(NULL, "audioCfg");
    if (!pJson)
    {
        LOG_PrintInfo("Not support logic audio!\n");
        return 0; 
    }

    if (0 == audioCtl_g.aioCtl.audioInChn)
    {
        audioCtl_g.logicChnInNum = 0;
    }
    else
    {
        pSubItem = CFG_GetItem(pJson, "audioIn");
        if (pSubItem)
        {
            audioCtl_g.logicChnInNum = cJSON_GetArraySize(pSubItem);
            for (i=0; i<audioCtl_g.logicChnInNum; i++)
            {
                pItem = cJSON_GetArrayItem(pSubItem, i);
                if (!pItem)
                {
                    LOG_PrintError("Fail to get config audioIn channel!\n");
                    return -1; 
                }

                audioCtl_g.logicChnInMask[i] = 
                    (int)strtoul(pItem->valuestring, NULL, 0);
            }
        }
    }

    if (0 == audioCtl_g.aioCtl.audioOutChn)
    {
        audioCtl_g.logicChnOutNum = 0;
    }
    else
    {
        pSubItem = CFG_GetItem(pJson, "audioOut");
        if (pSubItem)
        { 
            audioCtl_g.logicChnOutNum = cJSON_GetArraySize(pSubItem);
            for (i=0; i<audioCtl_g.logicChnOutNum; i++)
            {
                pItem = cJSON_GetArrayItem(pSubItem, i);
                if (!pItem)
                {
                    LOG_PrintError("Fail to get config audioIn channel!\n");
                    return -1; 
                }

                audioCtl_g.logicChnOutMask[i] = 
                    (int)strtoul(pItem->valuestring, NULL, 0);
            }
        }
    }

#ifdef UNSUPPORT_AAC
    audioCtl_g.aioCtl.supportAac = 0; 
#else
    pSubItem = cJSON_GetObjectItem(pJson, "supportAac");
    if (!pSubItem)
    {
        audioCtl_g.aioCtl.supportAac = 0; 
    }
    else
    {
        audioCtl_g.aioCtl.supportAac = pSubItem->valueint;
    }
#endif

    pSubItem = cJSON_GetObjectItem(pJson, "supportVqeAec");
    if (!pSubItem)
    {
        audioCtl_g.aioCtl.supportAec = 0; 
    }
    else
    {
        audioCtl_g.aioCtl.supportAec = pSubItem->valueint;
    }

    pSubItem = cJSON_GetObjectItem(pJson, "audioInMode");
    if (pSubItem)
    {
        audioCtl_g.aioCtl.audioInMode = pSubItem->valueint;
    }

#ifndef __HuaweiLite__
    cJSON_Delete(pJson);
#endif
#else
    audioCtl_g.logicChnInNum = 1;
    audioCtl_g.logicChnOutNum = 1;
#endif

    return 0;
}


/*******************************************************************************
  Function:     AUDIO_ReAudioDecFun
  Description:  解码录音命令执行函数
  Input:        - count: 参数个数
                - pInput: 参数字符串数组
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AUDIO_ReAudioDecFun(int count, char *pInput[])
{
    unsigned int streamId, frameNum, isPackData;
    ADEC_ctl_t *pAdecCtl; 

    if (count < 3 || count > 5)
    {
        LOG_Print("Usage:\n");
        LOG_Print("echo record streamId frameNum isPackData recordPath "\
                    "recordName > progress name \n");
        return -1;
    }

    streamId = (unsigned int)atoi(pInput[0]);
    frameNum = (unsigned int)atoi(pInput[1]);
    isPackData = (unsigned int)atoi(pInput[2]);

    if (streamId >= ADEC_STREAM_PER_CHN)
    {
        LOG_PrintError("streamId is invalid!\n");
        return -1;
    }

    pAdecCtl = audioCtl_g.pAdecCtls[streamId];
    if (!pAdecCtl)
    {
        LOG_PrintError("pAdecCtl is NULL!\n");
        return -1;
    }

    pAdecCtl->recordData.recordFd = -1;
    pAdecCtl->recordData.streamId = streamId;
    pAdecCtl->recordData.frameNum = frameNum;
    pAdecCtl->recordData.isPackData = isPackData;

    if (3 == count)
    {
        strcpy(pAdecCtl->recordData.recordPath, "./");
        sprintf(pAdecCtl->recordData.recordName, "audeodec_data_ch%d_%s", 
                    streamId, (isPackData == 1)?"dav":"raw");
    }
    else if (4 == count)
    {
        strcpy(pAdecCtl->recordData.recordPath, pInput[3]);
        sprintf(pAdecCtl->recordData.recordName, "audeodec_data_ch%d_%s", 
                    streamId, (isPackData == 1)?"dav":"raw");
    }
    else if (5 == count)
    {
        strcpy(pAdecCtl->recordData.recordPath, pInput[3]);
        strcpy(pAdecCtl->recordData.recordName, pInput[4]);
    }
    
    return 0;
}

/*******************************************************************************
  Function:     AUDIO_ReAudioEncFun
  Description:  编码录音命令执行函数
  Input:        - count: 参数个数
                - pInput: 参数字符串数组
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AUDIO_ReAudioEncFun(int count, char *pInput[])
{
    unsigned int streamId, frameNum, isPackData;
    AENC_ctl_t *pEncCtl; 

    if (count < 3 || count > 5)
    {
        LOG_Print("Usage:\n");
        LOG_Print("echo record streamId frameNum isPackData recordPath "\
                    "recordName > progress name \n");
        return -1;
    }

    streamId = (unsigned int)atoi(pInput[0]);
    frameNum = (unsigned int)atoi(pInput[1]);
    isPackData = (unsigned int)atoi(pInput[2]);

    if (streamId >= AENC_SUPPORT_CHN * AENC_STREAM_PER_CHN)
    {
        LOG_PrintError("streamId is invalid!\n");
        return -1;
    }

    pEncCtl = audioCtl_g.pEncCtls[streamId];
    if (!pEncCtl)
    {
        LOG_PrintError("pEncCtl is NULL!\n");
        return -1;
    }

    pEncCtl->recordData.recordFd = -1;
    pEncCtl->recordData.streamId = streamId;
    pEncCtl->recordData.frameNum = frameNum;
    pEncCtl->recordData.isPackData = isPackData;

    if (3 == count)
    {
        strcpy(pEncCtl->recordData.recordPath, "./");
        sprintf(pEncCtl->recordData.recordName, "audeoenc_data_ch%d_%s", 
                    streamId, (isPackData == 1)?"dav":"raw");
    }
    else if (4 == count)
    {
        strcpy(pEncCtl->recordData.recordPath, pInput[3]);
        sprintf(pEncCtl->recordData.recordName, "audeoenc_data_ch%d_%s", 
                    streamId, (isPackData == 1)?"dav":"raw");
    }
    else if (5 == count)
    {
        strcpy(pEncCtl->recordData.recordPath, pInput[3]);
        strcpy(pEncCtl->recordData.recordName, pInput[4]);
    }
    
    return 0;
}

/*******************************************************************************
  Function:     AUDIO_AudioEncFpsFun
  Description:  统计音频帧率命令执行函数
  Input:        - count: 参数个数
                - pInput: 参数字符串数组
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AUDIO_AudioEncFpsFun(int count, char *pInput[])
{
    unsigned int streamId, isStatFps;
    AENC_ctl_t *pEncCtl;
    
    if (count != 2)
    {
        LOG_Print("Usage:\n");
        LOG_Print("echo aencFps streamId isStatFps > progress name \n");
        return -1;
    }

    streamId = (unsigned int)atoi(pInput[0]);
    isStatFps = (unsigned int)atoi(pInput[1]);

    if (streamId >= AENC_SUPPORT_CHN * AENC_STREAM_PER_CHN)
    {
        LOG_PrintError("streamId is invalid!\n");
        return -1;
    }

    pEncCtl = audioCtl_g.pEncCtls[streamId];
    if (!pEncCtl)
    {
        LOG_PrintError("pEncCtl is NULL!\n");
        return -1;
    }

    /*pEncCtl->aencFps.streamId = streamId;
    pEncCtl->aencFps.isStatFps = isStatFps;
    pEncCtl->aencFps.frameCount = 0;
    pEncCtl->aencFps.oldTime = 0;*/

    return 0;
}

/*******************************************************************************
  Function:     VIDEO_GetIvsResultThd
  Description:  获取智能算法结果线程
  Input:        - parg: 参数
  Output:       无
  Return:       NULL
  Others:       无
*******************************************************************************/
static void *AUDIO_GetIasResultThd(void *parg)
{
    int ret;
    AudioAnalysePacket packet;
    AudioAnalyser *pAudioAnalyser = (AudioAnalyser *)parg;
    SYS_thdInfo_t thdInfo;

    strcpy(thdInfo.name, "iasThd");
    ret = SYS_DebugRegThd(&thdInfo);
    if (ret < 0)
    {
        LOG_PrintError("Fail to register cmd thread!\n");
    }

    while (1)
    {
        ret = pAudioAnalyser->getPacket(pAudioAnalyser, &packet);
        if (0 == ret)
        {            
            LOG_PrintWarn("eventNumber > %d, ruleType > %d\n", 
                            packet.eventNumber, packet.events[0].ruleType);
            
            pAudioAnalyser->releasePacket(pAudioAnalyser);
        }

        usleep(1000*20);
    }
    
    ret = SYS_DebugUnRegThd();
    if (ret < 0)
    {
        LOG_PrintError("Fail to unregister cmd thread!\n");
    }
    
    return NULL;
}

/*******************************************************************************
  Function:     AUDIO_RunIas
  Description:  运行智能算法
  Input:        - count: 参数个数
                - pInput: 参数字符串数组
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AUDIO_RunIas(int count, char *pInput[])
{
    int ret = 0;
    AudioAnalyseDesc AnalyseDesc;
    AudioAnalyser *pAudioAnalyser;
    AudioAnalyseFormat AnalyseFormat;
    AudioAnalyseRuleConfig AnalyseRuleCfg[2];
    pthread_t iasThd;

    if (count < 1)
    {
        LOG_Print("Usage:\n");
        LOG_Print("echo runIvs debug > hunter\n");
        return -1;
    }

    AnalyseDesc.channel = 0;
    AnalyseDesc.serviceTypeMask = AudioAnalyseServiceAQD;

    ret = createAudioAnalyser(&AnalyseDesc, &pAudioAnalyser);
    if (ret)
    {
        LOG_PrintError("create audio analyser failed!\n");
        return -1;
    }

    AnalyseFormat.numPerFrm = 320;
    AnalyseFormat.bitWidth = 16;
    AnalyseFormat.channel = 1;
    AnalyseFormat.samplerate = 8000;
    pAudioAnalyser->setFormat(pAudioAnalyser, &AnalyseFormat);
    pAudioAnalyser->start(pAudioAnalyser);

    AnalyseRuleCfg[0].ruleType = AudioAnalyseLoudly;
    AnalyseRuleCfg[0].config.audioLoudly.dbUpLimit = 77;

    AnalyseRuleCfg[1].ruleType = AudioAnalyseWeak;
    AnalyseRuleCfg[1].config.audioWeak.dbDownLimit = -77;

    pAudioAnalyser->setRuleConfig(pAudioAnalyser, 2, AnalyseRuleCfg);

    ret = pthread_create(&iasThd, 0, AUDIO_GetIasResultThd, pAudioAnalyser);
    if (ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        return -1;
    }
  
    return 0;
}

/*******************************************************************************
  Function:     AUDIO_Speak
  Description:  语音播放
  Input:        - count: 参数个数
                - pInput: 参数字符串数组
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AUDIO_Speak(int count, char *pInput[])
{
    int speakStatus;
    
    if (count != 2)
    {
        LOG_Print("Usage:\n");
        LOG_Print("echo speak 4 debug > progress name \n");
        return -1;
    }

    speakStatus = (int)atoi(pInput[0]);

    if (speakStatus == 0)
    {
        GPIO_Get(audioCtl_g.aioCtl.lineoutGpio);
        GPIO_SetDir(audioCtl_g.aioCtl.lineoutGpio, 1);
        GPIO_SetLevel(audioCtl_g.aioCtl.lineoutGpio, 0);
        GPIO_Put(audioCtl_g.aioCtl.lineoutGpio);
    }
    else
    {
        GPIO_Get(audioCtl_g.aioCtl.lineoutGpio);
        GPIO_SetDir(audioCtl_g.aioCtl.lineoutGpio, 1);
        GPIO_SetLevel(audioCtl_g.aioCtl.lineoutGpio, 0);
        GPIO_Put(audioCtl_g.aioCtl.lineoutGpio);
        usleep(10*1000);
        
        SYS_SetPulse(audioCtl_g.aioCtl.lineoutGpio, 4, speakStatus);
    }

    return 0;
}

/*******************************************************************************
  Function:     AUDIO_AoSaveFile
  Description:  保存音频解码后的pcm数据
  Input:        - count: 参数个数
                - pInput: 参数字符串数组
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AUDIO_AoSaveFile(int count, char *pInput[])
{
#ifdef HIMPP_V2_0
    int ret;
    int enable;
    int fileSize;
    AUDIO_SAVE_FILE_INFO_S saveFileInfo;
    memset(&saveFileInfo, 0, sizeof(saveFileInfo));

    if (count != 2)
    {
        LOG_Print("Usage:\n");
        LOG_Print("echo speak 4 debug > progress name \n");
        return -1;
    }

    enable = (int)atoi(pInput[0]);
    fileSize = (int)atoi(pInput[1]);

    saveFileInfo.bCfg = enable;
    memcpy(saveFileInfo.aFilePath, "/nfsroot/", strlen("/nfsroot/"));
    memcpy(saveFileInfo.aFileName, "audioOut", strlen("audioOut"));
    saveFileInfo.u32FileSize = fileSize;

    ret = HI_MPI_AO_SaveFile(audioCtl_g.aioCtl.aoDevId, 
                                audioCtl_g.aioCtl.aoChn, &saveFileInfo);
    if (ret)
    {
        LOG_PrintError("HI_MPI_AO_SaveFile faile!(0x%x)\n", ret);
        return -1;
    }
#endif

    return 0;
}

/*******************************************************************************
  Function:     AUDIO_RegCmd
  Description:  注册调试命令
  Input:        无
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AUDIO_RegCmd(void)
{
    SYS_cmdParams_t cmdParams;

    memset(&cmdParams, 0, sizeof(SYS_cmdParams_t));
    strcpy(cmdParams.cmdName, "reAudioDec");
    cmdParams.func = AUDIO_ReAudioDecFun;
    SYS_DebugRegCmd(&cmdParams); 

    memset(&cmdParams, 0, sizeof(SYS_cmdParams_t));
    strcpy(cmdParams.cmdName, "reAudioEnc");
    cmdParams.func = AUDIO_ReAudioEncFun;
    SYS_DebugRegCmd(&cmdParams);

    memset(&cmdParams, 0, sizeof(SYS_cmdParams_t));
    strcpy(cmdParams.cmdName, "aencFps");
    cmdParams.func = AUDIO_AudioEncFpsFun;
    SYS_DebugRegCmd(&cmdParams);

    memset(&cmdParams, 0, sizeof(SYS_cmdParams_t));
    strcpy(cmdParams.cmdName, "runIas");
    cmdParams.func = AUDIO_RunIas;
    SYS_DebugRegCmd(&cmdParams);

    memset(&cmdParams, 0, sizeof(SYS_cmdParams_t));
    strcpy(cmdParams.cmdName, "speak");
    cmdParams.func = AUDIO_Speak;
    SYS_DebugRegCmd(&cmdParams);

    memset(&cmdParams, 0, sizeof(SYS_cmdParams_t));
    strcpy(cmdParams.cmdName, "saveAo");
    cmdParams.func = AUDIO_AoSaveFile;
    SYS_DebugRegCmd(&cmdParams);
 
    return 0;
}

/*******************************************************************************
  Function:     AUDIO_AudioInThd
  Description:  音频输入linein micin判断线程
  Input:        - parg: 参数指针
  Output:       无
  Return:       NULL
  Others:       无
*******************************************************************************/
void *AUDIO_AudioInThd(void *parg)
{
    int ret;
    unsigned int level = 0;
    AIO_ctl_t *pAioCtl = (AIO_ctl_t *)parg;

#ifndef __HuaweiLite__
    SYS_thdInfo_t thdInfo;
    strcpy(thdInfo.name, "audioin");
    SYS_DebugRegThd(&thdInfo);
#endif

    while(1)
    {
        if (pAioCtl->lineinGpio >= 0)
        {
            GPIO_GetLevel(pAioCtl->lineinGpio, &level);
        }
        else if (pAioCtl->lineinAdcChn >= 0)
        {
            unsigned int value = 0;
            
            //ADC_GetValue(pAioCtl->lineinHadc, &value);
            level = (value >= LINEIN_ADC_THRESHOLD)?1:0;
        }

        if (level != pAioCtl->gpioLevel)
        {
            pthread_mutex_lock(&audioCtl_g.audioMutex);
                        
            pAioCtl->gpioLevel = level;
            pAioCtl->audioInTrack = !pAioCtl->audioInTrack;
            pAioCtl->audioInMode = !pAioCtl->audioInMode;

            if (0 == audioCtl_g.bCreatAudio)
            {
                ret = AUDIO_StopAll();
                if (ret)
                {
                    LOG_PrintError("Fail to stop all aenc chn!\n");
                    pthread_mutex_unlock(&audioCtl_g.audioMutex);
                    goto exit_out;
                }

                pAioCtl->aiChn = pAioCtl->audioInTrack;

                ret = AUDIO_StartAll();
                if (ret)
                {
                    LOG_PrintError("Fail to start all aenc chn!\n");
                    pthread_mutex_unlock(&audioCtl_g.audioMutex);
                    goto exit_out;
                }
            }
            else
            {
                pAioCtl->aiChn = pAioCtl->audioInTrack;
            }
    
            pthread_mutex_unlock(&audioCtl_g.audioMutex);
        }
        
        sleep(1);
    }

exit_out:
#ifndef __HuaweiLite__
    SYS_DebugUnRegThd();
#endif
    return NULL;
}

/*******************************************************************************
  Function:     AUDIO_LineMicInit
  Description:  音频输入linein micin判断
  Input:        - pAioCtl: AIO_ctl_t结构体指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AUDIO_LineMicInit(AIO_ctl_t *pAioCtl)
{
    int ret;
    
    if (pAioCtl->lineinGpio >= 0)
    {
        pAioCtl->gpioLevel = pAioCtl->lineinLevel;
    }
    else if (pAioCtl->lineinAdcChn >= 0)
    {
        ADC_openParam_t adcParam;

        adcParam.chn = pAioCtl->lineinAdcChn;
        adcParam.bits = LINEIN_ADC_BITS;
        adcParam.mode = ADC_MODE_CLCYE;
        adcParam.fscan = 2;
        adcParam.getValue = NULL;
        
        pAioCtl->lineinHadc = ADC_Open(&adcParam);

        ADC_Start(pAioCtl->lineinHadc);

        pAioCtl->gpioLevel = pAioCtl->lineinAdcLevel;
    }

    if ((pAioCtl->lineinGpio >= 0) || (pAioCtl->lineinAdcChn >= 0))
    {
        ret = pthread_create(&pAioCtl->audioInThd, 0, 
                                AUDIO_AudioInThd, pAioCtl);
        if (ret)
        {
            LOG_PrintError("can't create thread: %s\n", strerror(ret));
            return -1;
        }
    }

    return 0;
}

int AUDIO_micInit(int sampleRate, int channels)
{
	int ret = -1;
	AI_CHN_ATTR_S *ai_attr = &audioCtl_g.ai_attr[AUDIO_AI_CH];
	AO_CHN_ATTR_S ao_attr = {0};
	
	//0. 6个mic采集
	MPP_CHN_S mpp_chn_ai;
	int u32NbSamples = 0;

	switch (sampleRate)
	{
		case 16000:
			u32NbSamples = 256;
			break;
			
		case 32000:
			u32NbSamples = 512;
			break;
			
		case 48000:
			u32NbSamples = 768;
			break;
		default:
			LOG_PrintError("not support sampleRate %d \n", sampleRate);
			break;
	}
	mpp_chn_ai.enModId = RK_ID_AI;
	mpp_chn_ai.s32ChnId = 0;

	ai_attr->pcAudioNode = "hw:0,0";
	ai_attr->enSampleFormat = RK_SAMPLE_FMT_S16;
	ai_attr->u32NbSamples = u32NbSamples;
	ai_attr->u32SampleRate = sampleRate;
	ai_attr->u32Channels   = channels;
	ai_attr->enAiLayout = AI_LAYOUT_NORMAL;

	ao_attr.pcAudioNode = "plughw:0,0";
	ao_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
	ao_attr.u32NbSamples = u32NbSamples;
	ao_attr.u32SampleRate = sampleRate;
	ao_attr.u32Channels = 1;
	
	/* 开启ao，只是为了设置i2s频率 */
	ret = RK_MPI_AO_SetChnAttr(AUDIO_AO_CH, &ao_attr);
	if (ret)
	{
		LOG_PrintError("AO etChnAttr err:%d\n", ret);
		return -1;
	}

	ret = RK_MPI_AO_EnableChn(AUDIO_AO_CH);
	if (ret)
	{
		LOG_PrintError("AO enable err:%d\n", ret);
		return -1;
	}

	// 1. create AI
	ret = RK_MPI_AI_SetChnAttr(AUDIO_AI_CH, ai_attr);
	if (ret)
	{
		LOG_PrintError("SetChnAttr err:%d\n", ret);
		return -1;
	}
		
	ret = RK_MPI_AI_EnableChn(AUDIO_AI_CH);
	if (ret)
	{
		LOG_PrintError("3-ai enable err:%d\n", ret);
		return -1;
	}

	ret = RK_MPI_AI_StartStream(AUDIO_AI_CH);
	if (ret) 
	{
	  LOG_PrintError("Start AI failed! ret=%d\n", ret);
	  return -1;
	}

	LOG_PrintInfo("Audio Mic init Ok\n");
	return 0;
}

int AUDIO_micDeInit(void)
{
	int ret = -1;

	ret =  RK_MPI_AO_ClearChnBuf(AUDIO_AO_CH);
	if (ret) 
	{
	    LOG_PrintError("Start AI failed! ret=%d\n", ret);
	    return -1;
	}

	ret = RK_MPI_AO_DisableChn(AUDIO_AO_CH);
	if (ret)
	{
		LOG_PrintError("AO enable err:%d\n", ret);
		return -1;
	}
		
	ret = RK_MPI_AI_DisableChn(AUDIO_AI_CH);
	if (ret)
	{
		LOG_PrintError("3-ai enable err:%d\n", ret);
		return -1;
	}
	LOG_PrintInfo("Audio Line in/out Deinit Ok\n");

	return 0;
}

int AUDIO_lineInOutInit(int sampleRate, int channels)
{
	int ret = -1;
	AI_CHN_ATTR_S *ai_attr = &audioCtl_g.ai_attr[AUDIO_AI_LINEIN_CH];
	AO_CHN_ATTR_S ao_attr = {0};
	int u32NbSamples = 0;

	switch (sampleRate)
	{
		case 16000:
			u32NbSamples = 256;
			break;
			
		case 32000:
			u32NbSamples = 512;
			break;
			
		case 48000:
			u32NbSamples = 768;
			break;
		default:
			LOG_PrintError("not support sampleRate %d \n", sampleRate);
			break;
	}
	
	//1. line in/out设备
    ai_attr->pcAudioNode = "hw:1,0";
	ai_attr->enSampleFormat = RK_SAMPLE_FMT_S16;
	ai_attr->u32NbSamples = u32NbSamples;
	ai_attr->u32SampleRate = sampleRate;
	ai_attr->u32Channels = channels;
	ai_attr->enAiLayout = AI_LAYOUT_NORMAL;

	ao_attr.pcAudioNode = "hw:1,0";
	ao_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
	ao_attr.u32NbSamples = u32NbSamples;
	ao_attr.u32SampleRate = sampleRate;
	ao_attr.u32Channels = channels;

	ret = RK_MPI_AO_SetChnAttr(AUDIO_AO_LINEOUT_CH, &ao_attr);
	if (ret)
	{
		LOG_PrintError("AO etChnAttr err:%d\n", ret);
		return -1;
	}

	ret = RK_MPI_AO_EnableChn(AUDIO_AO_LINEOUT_CH);
	if (ret)
	{
		LOG_PrintError("AO enable err:%d\n", ret);
		return -1;
	}
		
#if 0
	//音量会设置失败
	RK_S32 s32CurrentVolmue = 0;
	ret = RK_MPI_AO_GetVolume(AUDIO_AO_LINEOUT_CH, &s32CurrentVolmue);
	if (ret) {
		printf("Get Volume(before) failed! ret=%d\n", ret);
		return -1;
	}
	printf("#Before Volume set, volume=%d\n", s32CurrentVolmue);

	ret = RK_MPI_AO_SetVolume(AUDIO_AO_LINEOUT_CH, 70);
	if (ret) {
		printf("Set Volume failed! ret=%d\n", ret);
		return -1;
	}

	s32CurrentVolmue = 0;
	ret = RK_MPI_AO_GetVolume(AUDIO_AO_LINEOUT_CH, &s32CurrentVolmue);
	if (ret) {
		printf("Get Volume(after) failed! ret=%d\n", ret);
		return -1;
	}
	printf("#After Volume set, volume=%d\n", s32CurrentVolmue);
#endif

	// 1. create AI
	ret = RK_MPI_AI_SetChnAttr(AUDIO_AI_LINEIN_CH, ai_attr);
	if (ret)
	{
		LOG_PrintError("SetChnAttr err:%d\n", ret);
		return -1;
	}
		
	ret = RK_MPI_AI_EnableChn(AUDIO_AI_LINEIN_CH);
	if (ret)
	{
		LOG_PrintError("3-ai enable err:%d\n", ret);
		return -1;
	}

	ret = RK_MPI_AI_StartStream(AUDIO_AI_LINEIN_CH);
	if (ret) 
	{
	  LOG_PrintError("Start AI failed! ret=%d\n", ret);
	  return -1;
	}
	LOG_PrintInfo("Audio Line in/out init Ok\n");

	return 0;
}

int AUDIO_lineInOutDeInit(void)
{
	int ret = -1;

	ret =  RK_MPI_AO_ClearChnBuf(AUDIO_AO_LINEOUT_CH);
	if (ret) 
	{
	    LOG_PrintError("Start AI failed! ret=%d\n", ret);
	    return -1;
	}

	ret = RK_MPI_AO_DisableChn(AUDIO_AO_LINEOUT_CH);
	if (ret)
	{
		LOG_PrintError("AO enable err:%d\n", ret);
		return -1;
	}
		
	ret = RK_MPI_AI_DisableChn(AUDIO_AI_LINEIN_CH);
	if (ret)
	{
		LOG_PrintError("3-ai enable err:%d\n", ret);
		return -1;
	}
	LOG_PrintInfo("Audio Line in/out Deinit Ok\n");

	return 0;
}

int AUDIO_uacInit(Audio_uac_card_info *info)
{
	int ret = -1;
	AENC_ctl_t *pAencCtl = NULL;
	AI_CHN_ATTR_S *ai_attr = &audioCtl_g.ai_attr[AUDIO_AI_UAC_CH];
	AO_CHN_ATTR_S ao_attr = {0};
	
    ai_attr->pcAudioNode = "hw:2,0";
	ai_attr->enSampleFormat = RK_SAMPLE_FMT_S16;
	ai_attr->u32SampleRate = info->aiSampleRate;
	ai_attr->u32Channels = info->aiChn;
	ai_attr->u32NbSamples = info->aiSampleNum;
	ai_attr->enAiLayout = AI_LAYOUT_NORMAL;

	ao_attr.pcAudioNode = "hw:2,0";
	ao_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
	ao_attr.u32SampleRate = info->aoSampleRate;
	ao_attr.u32Channels = info->aoChn;
	ao_attr.u32NbSamples = info->aoSampleNum;
#if 0
	ret = RK_MPI_AO_SetChnAttr(AUDIO_AO_UAC_CH, &ao_attr);
	if (ret)
	{
		LOG_PrintError("AO etChnAttr err:%d\n", ret);
		return -1;
	}

	ret = RK_MPI_AO_EnableChn(AUDIO_AO_UAC_CH);
	if (ret)
	{
		LOG_PrintError("AO enable err:%d\n", ret);
		return -1;
	}
#endif
	// 1. create AI
	ret = RK_MPI_AI_SetChnAttr(AUDIO_AI_UAC_CH, ai_attr);
	if (ret)
	{
		LOG_PrintError("SetChnAttr err:%d\n", ret);
		return -1;
	}
		
	ret = RK_MPI_AI_EnableChn(AUDIO_AI_UAC_CH);
	if (ret)
	{
		LOG_PrintError("3-ai enable err:%d\n", ret);
		return -1;
	}

	ret = RK_MPI_AI_StartStream(AUDIO_AI_UAC_CH);
	if (ret) 
	{
	    LOG_PrintError("Start AI failed! ret=%d\n", ret);
	    return -1;
	}
	pAencCtl = audioCtl_g.pEncCtls[AUDIO_AI_UAC_CH];
	if (pAencCtl)
	{
		//pAencCtl->u32SampleRate = ai_attr->u32SampleRate;
		//pAencCtl->chnNum        = ai_attr->u32Channels;
	}
	LOG_PrintInfo("Audio Uac Init Ok!\n");
	
	return 0;
}

int AUDIO_uacDeInit(void)
{
	int ret = -1;
#if 0
	ret =  RK_MPI_AO_ClearChnBuf(AUDIO_AI_UAC_CH);
	if (ret) 
	{
	    LOG_PrintError("Start AI failed! ret=%d\n", ret);
	    return -1;
	}

	ret = RK_MPI_AO_DisableChn(AUDIO_AO_UAC_CH);
	if (ret)
	{
		LOG_PrintError("AO enable err:%d\n", ret);
		return -1;
	}
#endif
	ret = RK_MPI_AI_DisableChn(AUDIO_AI_UAC_CH);
	if (ret)
	{
		LOG_PrintError("3-ai enable err:%d\n", ret);
		return -1;
	}
	LOG_PrintInfo("Audio Uac Deinit Ok\n");
	return 0;
}

int AUDIO_initAACEnc(int u32SampleRate, int u32Channels, int outFormat)
{
	//aac encode init
	audioCtl_g.pAacCfg.sampleRate = u32SampleRate;
    audioCtl_g.pAacCfg.channels   = u32Channels;
    audioCtl_g.pAacCfg.bitWidth   = 16;
    audioCtl_g.pAacCfg.outputFormat = outFormat;
	audioCtl_g.pAacCtl = AAC_EncCreat(&audioCtl_g.pAacCfg);
	if (!audioCtl_g.pAacCtl)
	{
	    LOG_PrintError("AAC_EncCreat failed!\n");
	    return -1;
	}
	LOG_PrintInfo("Audio AAC encode init Ok\n");
	return 0;
}

int AUDIO_putAACPkt(char *pBuf, int len)
{
	int ret = 0;
	
	ret = AAC_EncSendFrame(audioCtl_g.pAacCtl, pBuf, len);
    if (ret)
    {
        LOG_PrintError("ERROR: AAC_EncSendFrame\n");
		return -1;
    }
	return 0;
}

int AUDIO_getAACPkt(char *pBuf, int *len)
{
	int ret = 0;
	AAC_aencStream_t aencStream;
	
	ret = AAC_EncGetStream(audioCtl_g.pAacCtl, &aencStream);
	if (ret)
	{
		return -1;
	}
	memcpy(pBuf, aencStream.pData, aencStream.dataSize);
	*len = aencStream.dataSize;
	return 0;
}


int AUDIO_getAACDecoderSpecificInfo(char **ppBuffer, unsigned long *pSize)
{
	return faacEncGetDecoderSpecificInfo(audioCtl_g.pAacCtl->hEncoder, ppBuffer, pSize);
}


static int AUDIO_CommposeInit()
{
    /*初始化音频混音动作*/
    if(hasCreated_s == 0)
    {
        AMIX_InitStreamCompose();
        hasCreated_s = 1;
    }

    return 1;
}

int AUDIO_GetResamplerLen(int sampleRate, int depth, int channels, int *dealLen)
{
    if (sampleRate == AUDIO_RESAMPLE_44100HZ)
    {
        *dealLen = sampleRate* channels* (depth / 8)* AUDIO_ALGO_44100_TIME / 1000;  //44100HZ need per frame 10ms to resample
    }
    else
    {
        *dealLen = sampleRate * channels * (depth / 8) * AUDIO_ALGO_TIME / 1000; //音频算法目前只支持16ms每一帧
    }
	return 0;
}


int AUDIO_GetOutSamples(int sampleRate, int *nbSamples)
{
    switch (sampleRate)
	{
		case 8000:
			*nbSamples = 128;
			break;
			
		case 16000:
			*nbSamples = 256;
			break;
			
		case 32000:
			*nbSamples = 512;
			break;
			
		case 48000:
			*nbSamples = 768;
			break;
		default:
			LOG_PrintError("not support sampleRate %d \n", sampleRate);
			return -1;
	}

	return 0;
}

int AUDIO_GetOutNode(StreamOutInterface interface, char *node)
{
    char mark[32] = {0};
    switch(interface)
    { 
        case LINE_OUT:
        case HDMI_OUT:
        {
            memcpy(mark, "MicArray_L", sizeof(mark));
            break;
        }
        case BLUETOOTH_OUT:        
        case HORN_OUT:

        default:
			LOG_PrintError("not support StreamOutInterface %d \n", interface);
			return -1;
	}
	   
    char line[256] = {0};
    char member[512] ={0};
    if(access(asoundPath, F_OK)){
            LOG_PrintError("not exist %s.\n", asoundPath);
            return -1;
    }
    //通过fopen函数创建一个线程执行命令
    FILE *fp = fopen(asoundPath, "r");
    if(!fp){
            LOG_PrintError("Fail to open %s.\n", asoundPath);
            return -1;
    }
    //读取命令的返回值
    while(fgets(line, sizeof(line), fp)){
            strcat(member, line);
            if(fgets(line, sizeof(line), fp)){
                    strcat(member, line);
            }
            
            char *findPos = strstr(member, mark);
            if( findPos != NULL){
                fclose(fp);
                int id = member[1] - 48;
                char number[8] = {0};
                sprintf(number, "%d", id);
                
                strcat(node, "hw:");
                strcat(node, number);

                strcat(node, ",0");
                return 0;
            }
            memset(member, 0,sizeof(member));
    }
    fclose(fp);

	return -1;
}


/*******************************************************************************
  Function:     AUDIO_Init
  Description:  audio模块初始化
  Input:        无
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int AUDIO_Init(_Audio_ChnAttr *audioAttr)
{
    int ret;

#if 1 
	AUDIO_CommposeInit();
#else
    audioCtl_g.bCreatAudio = 1;
    audioCtl_g.isAcodecReset = 1;
    audioCtl_g.isSetVqe = 0;
    audioCtl_g.aioCtl.lineinGpio = -1;
    audioCtl_g.aioCtl.lineinAdcChn = -1;
    audioCtl_g.aioCtl.lineoutType = -1;

#ifndef __HuaweiLite__
    /*ret = LOG_Init();
    if (ret)
    {
        LOG_PrintError("Fail to init log!\n");
        return -1;
    }*/
    
    ret = CFG_Init();
    if (ret)
    {
        LOG_PrintError("Fail to init cfg!\n");
        return -1;
    }
#endif

    /*ret = AUDIO_GetConfig();
    if (ret)
    {
        LOG_PrintError("Fail to get config!\n");
        return -1;
    }*/

#ifndef __HuaweiLite__
    //CFG_Exit();
#endif

    pthread_mutex_init(&audioCtl_g.aiMutex, NULL);
    pthread_mutex_init(&audioCtl_g.audioMutex, NULL);
    pthread_mutex_init(&audioCtl_g.aoMutex, NULL);
    pthread_mutex_init(&audioCtl_g.aiAencMutex, NULL);
    pthread_mutex_init(&audioCtl_g.adecMutex, NULL);
#ifdef BUILD_IAS
    pthread_mutex_init(&audioCtl_g.analyserMutex, NULL);
#endif

    ret = AUDIO_GetCfg(&audioCtl_g.aioCtl);
    if (ret)
    {
        LOG_PrintError("Fail to get audio config!\n");
        return -1;
    }

    /*ret = AUDIO_LineMicInit(&audioCtl_g.aioCtl);
    if (ret)
    {
        LOG_PrintError("Faio to init line mic!\n");
        return -1;
    }*/

    ret = AIN_CreateDev(audioCtl_g.aioCtl.aiDevId[AI_DEV_ID0], &audioCtl_g.aioCtl.aiAttr[AI_DEV_ID0]);
    if (ret)
    {
        LOG_PrintError("AIN_CreateDev faile!\n");
        return -1;
    }

    ret = AIN_CreateDev(audioCtl_g.aioCtl.aiDevId[AI_DEV_ID1], &audioCtl_g.aioCtl.aiAttr[AI_DEV_ID1]);
    if (ret)
    {
        LOG_PrintError("AIN_CreateDev faile!\n");
        return -1;
    }

    ret = AOUT_CreateDev(audioCtl_g.aioCtl.aoDevId, &audioCtl_g.aioCtl.aoAttr);
    if (ret)
    {
        LOG_PrintError("AOUT_CreateDev faile!\n");
        return -1;
    }

#ifndef __HuaweiLite__
    AUDIO_RegCmd();
#endif
#endif    
    return 0;
}

/*******************************************************************************
  Function:     AUDIO_SysInit
  Description:  mpi系统初始化，只在测试程序里调用，hunter在libvideo做初始化
  Input:        无
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int AUDIO_SysInit(void)
{
#if 0

#if defined(AUDIO_HI3559AV100)||defined(AUDIO_HI3516CV500)||defined(AUDIO_HI3516EV200)||defined(AUDIO_HI3519AV100)
	VB_CONFIG_S stVbConf;
    MPP_SYS_CONFIG_S stSysConf = {0};
#else
    VB_CONF_S stVbConf;
    MPP_SYS_CONF_S stSysConf = {0};
#endif
    HI_S32 s32Ret = -1;

    memset(&stVbConf, 0, sizeof(stVbConf));

    HI_MPI_SYS_Exit();
    HI_MPI_VB_Exit();
	
#if defined(AUDIO_HI3559AV100)||defined(AUDIO_HI3516CV500)||defined(AUDIO_HI3516EV200)||defined(AUDIO_HI3519AV100)
	s32Ret = HI_MPI_VB_SetConfig(&stVbConf);
#else
    s32Ret = HI_MPI_VB_SetConf(&stVbConf);
#endif
    if (HI_SUCCESS != s32Ret)
    {
        LOG_PrintError("HI_MPI_VB_SetConf failed!\n");
        return -1;
    }

    s32Ret = HI_MPI_VB_Init();
    if (HI_SUCCESS != s32Ret)
    {
        LOG_PrintError("HI_MPI_VB_Init failed!\n");
        return -1;
    }

#if defined(AUDIO_HI3559AV100)||defined(AUDIO_HI3516CV500)||defined(AUDIO_HI3516EV200)||defined(AUDIO_HI3519AV100)
	stSysConf.u32Align = 64;
    s32Ret = HI_MPI_SYS_SetConfig(&stSysConf);
#else
    stSysConf.u32AlignWidth = 64;
    s32Ret = HI_MPI_SYS_SetConf(&stSysConf);
#endif
    if (HI_SUCCESS != s32Ret)
    {
        LOG_PrintError("HI_MPI_SYS_SetConf failed\n");
        return -1;
    }

    s32Ret = HI_MPI_SYS_Init();
    if (HI_SUCCESS != s32Ret)
    {
        LOG_PrintError("HI_MPI_SYS_Init failed!\n");
        return -1;
    }
#endif
    return 0;
}

